<?php
/**
 * Created by PhpStorm.
 * User: edmmss
 * Date: 2021/9/27
 * Time: 16:25
 */

namespace Edmmss\Easyswoole\Task\Client;

use Edmmss\Common\SerializerPack;

class Client extends ClientAbstract
{
    /**
     * 默认同步等待时间
     */
    const DEFAULT_SYNC_WAIT_TIME = 3;

    /**
     * 重新连接次数
     */
    const AGAIN_CONNECT_NUMBER = 3;

    /**
     * 初始化计数次数
     */
    const INIT_NUMBER = 1;

    /**
     * rpc请求
     *
     * @date   2021/9/28
     * @param $call
     * @param $taskType
     * @param array $params
     * @return Response
     * @throws \Exception
     * @author edmmss
     */
    public function request($call, $taskType, $params = [])
    {
        $client = new \swoole_client(SWOOLE_SOCK_TCP);

        $client->set([
            'open_length_check'     => $this->openLengthCheck,
            'package_length_type'   => $this->packageLengthType,
            'package_length_offset' => $this->packageLengthOffset,
            'package_body_offset'   => $this->packageBodyOffset,
            'package_max_length'    => $this->packageMaxLength,
        ]);

        $data = ['call' => $call, 'params' => $params, 'taskType' => $taskType];
        $sendData = SerializerPack::encode($data, SerializerPack::SERIALIZER_TYPE_BASE, self::getRequestId());

        $connectResult = false;
        $number = self::INIT_NUMBER;
        // 重连机制
        while ($number <= self::AGAIN_CONNECT_NUMBER && $connectResult === false) {
            if ($number != self::INIT_NUMBER) {
                // 如果不是第一次，强制销毁socket
                $client->close(true);
            }

            // connect方法会阻塞，直到连接成功并返回true
            $connectResult = $client->connect($this->serverHost, $this->serverPort);
            if ($connectResult !== false) {
                $client->send($sendData);
                $this->originalResult = $client->recv();
                $response = $this->finish();
                $client->close();

                return $response;
            }
            // 记录重连次数
            $number++;
        }

        // 如果跑出来了肯定是超过重连次数并且返回的链接信息都是错误的
        throw new \Exception('rpcClient syncConnect failed');
    }

    /**
     * 请求完成
     *
     * @date   2021/9/28
     * @return Response
     * @throws \Exception
     * @author edmmss
     */
    private function finish()
    {
        $result = SerializerPack::decode($this->originalResult);

        $header = $result['header'];
        $data = $result['data'];

        return new Response($data, $header);
    }
}